package ca.etsmtl.log660.dao;

import java.util.ArrayList;
import java.util.List;

import org.hibernate.Session;

import ca.etsmtl.log660.configuration.SessionFactoryHelper;
import ca.etsmtl.log660.entity.Film;

class FilmDAO {
	
	public Film getById(Long id) {
		Film film = null;
		
		Session session = SessionFactoryHelper.getSessionFactory().openSession();
		session.beginTransaction();
		film = (Film) session.get(Film.class, id);
		session.getTransaction().commit();
		session.close();

		return film;
	}
	
	@SuppressWarnings("unchecked")
	public List<Film> search(
			List<String> titlesFilters,
			String startYearFilter,
			String endYearFilter,
			List<String> prodCountriesFilters,
			List<String> langagesFilters,
			List<String> genresFilters,
			List<String> realisatorsFilters,
			List<String> actorsFilters
	) {
		String query = this.buildSearchQuery(titlesFilters, startYearFilter, endYearFilter, prodCountriesFilters, langagesFilters, genresFilters, realisatorsFilters, actorsFilters);
		
		List<Film> films = new ArrayList<Film>();
		Session session = SessionFactoryHelper.getSessionFactory().openSession();
		session.beginTransaction();
		List<Object> result = session.createQuery(query).list();
		session.getTransaction().commit();
		session.close();
		
		for (Object object : result) {
			Film filmToAdd = null;
			if (object instanceof Film) {
				filmToAdd = (Film) object;
				if (!films.contains(filmToAdd)) {
					films.add(filmToAdd);
				}
			} else {
				Object[] arrayObject = (Object[]) object;
				Object object0 = arrayObject[0];
				if (object0 instanceof Film) {
					filmToAdd = (Film) object0;
					if (!films.contains(filmToAdd)) {
						films.add(filmToAdd);
					}
				}
			}
		}
		
		return films;
	}
	
	private String buildSearchQuery(
			List<String> titlesFilters,
			String startYearFilter,
			String endYearFilter,
			List<String> prodCountriesFilters,
			List<String> langagesFilters,
			List<String> genresFilters,
			List<String> realisatorsFilters,
			List<String> actorsFilters
	) {
		String noParamQuery = "FROM Film f";
		String query = "FROM Film f ";
		boolean hasParameter = false;
		boolean addOrClause = false;
		boolean addAndClause = false;
		
		if (!prodCountriesFilters.isEmpty()) {
			query += "JOIN f.paysDeProduction pdp ";
		}
		if (!genresFilters.isEmpty()) {
			query += "JOIN f.genre g ";
		}
		if (!realisatorsFilters.isEmpty()) {
			query += "JOIN f.realisateur r ";
		}
		if (!actorsFilters.isEmpty()) {
			query += "JOIN f.roles ro JOIN ro.acteur a ";
		}
		query += "WHERE ";
		
		// Ajoute les filtres par le titre du film
		if (!titlesFilters.isEmpty()) {
			hasParameter = true;
			addOrClause = false;
			
			if (addAndClause) {
				query += "AND ";
			}
			
			query += "(";
			
			for (String title : titlesFilters) {
				if (addOrClause) {
					query += "OR ";
				}
				query += "LOWER(f.titre) LIKE '%" + title.toLowerCase() + "%' ";
				addOrClause = true;
			}
			
			query += ") ";
			addAndClause = true;
		}
		
		// Ajoute une date minimum
		if (startYearFilter != null) {
			hasParameter = true;
			
			if (addAndClause) {
				query += "AND ";
			}
			query += "(f.anneeDeSortie >= to_date('" + startYearFilter + "', 'yyyy')) ";
			
			addAndClause = true;
		}
		
		// Ajoute une date maximum
		if (endYearFilter != null) {
			hasParameter = true;
			
			if (addAndClause) {
				query += "AND ";
			}
			query += "(f.anneeDeSortie <= to_date('" + endYearFilter + "', 'yyyy')) ";
			
			addAndClause = true;
		}
		
		// Ajoute les filtres par le pays de production
		if (!prodCountriesFilters.isEmpty()) {
			hasParameter = true;
			addOrClause = false;
			
			if (addAndClause) {
				query += "AND ";
			}
			
			query += "(";
			
			for (String country : prodCountriesFilters) {
				if (addOrClause) {
					query += "OR ";
				}
				query += "LOWER(pdp.nom) LIKE '%" + country.toLowerCase() + "%' ";
				addOrClause = true;
			}
			
			query += ") ";
			addAndClause = true;
		}
		
		// Ajoute les filtres par langue
		if (!langagesFilters.isEmpty()) {
			hasParameter = true;
			addOrClause = false;
			
			if (addAndClause) {
				query += "AND ";
			}
			
			query += "(";
			
			for (String langage : langagesFilters) {
				if (addOrClause) {
					query += "OR ";
				}
				query += "LOWER(f.langue) LIKE '%" + langage.toLowerCase() + "%' ";
				addOrClause = true;
			}
			
			query += ") ";
			addAndClause = true;
		}
		
		// Ajoute les filtres par genre
		if (!genresFilters.isEmpty()) {
			hasParameter = true;
			addOrClause = false;
			
			if (addAndClause) {
				query += "AND ";
			}
			
			query += "(";
			
			for (String genre : genresFilters) {
				if (addOrClause) {
					query += "OR ";
				}
				query += "LOWER(g.nom) LIKE '%" + genre.toLowerCase() + "%' ";
				addOrClause = true;
			}
			
			query += ") ";
			addAndClause = true;
		}
		
		// Ajoute les filtres par realisateur
		if (!realisatorsFilters.isEmpty()) {
			hasParameter = true;
			addOrClause = false;
			
			if (addAndClause) {
				query += "AND ";
			}
			
			query += "(";
			
			for (String real : realisatorsFilters) {
				if (addOrClause) {
					query += "OR ";
				}
				query += "LOWER(r.nom) LIKE '%" + real.toLowerCase() + "%' ";
				addOrClause = true;
			}
			
			query += ") ";
			addAndClause = true;
		}
		
		// Ajoute les filtres par acteur
		if (!actorsFilters.isEmpty()) {
			hasParameter = true;
			addOrClause = false;
			
			if (addAndClause) {
				query += "AND ";
			}
			
			query += "(";
			
			for (String actor : actorsFilters) {
				if (addOrClause) {
					query += "OR ";
				}
				query += "LOWER(a.nom) LIKE '%" + actor.toLowerCase() + "%' ";
				addOrClause = true;
			}
			
			query += ") ";
			addAndClause = true;
		}
		
		if (!hasParameter) {
			query = noParamQuery;
		}
		return query;
	}
}
